#include <stdio.h>

//#include <QtWidgets/QTextDocument>
#include <QtWidgets/QTextEdit>
//#include <QtWidgets/QTextBlock>
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QMessageBox>

#include <QtCore/QTextStream>
#include <QtCore/QFile>

#include <QKeyEvent>

#include "WA_MainWin.h"
#include "WA_DlgTarget.h"

const int WriteAttackMainWin::mascotFrames[12][10] =
{
	// IDLE,     ATTACK,     HAPPY,     OUCH,     DEAD
	{ 0, 1,     1, 2,       1,3,        0,4,      5,6 }, // yoshi
	{ 0, 1,     2, 3,       1,3,        0,4,      5,6 }, // cloudbaby
	{ 0, 1,     1, 2,       1,3,        0,4,      5,6 }, // dogthing
	{ 0, 1,     1, 2,       1,3,        0,4,      5,6 }, // bird
	{ 0, 1,     1, 2,       1,3,        0,4,      5,6 }, // frog
	{ 0, 1,     3, 2,       3,4,        0,5,      6,7 }, // blargg
	{ 0, 1,     5, 2,       3,4,        5,5,      6,7 }, // fish
	{ 0, 1,     1, 2,       1,3,        0,4,      5,6 }, // penguin
	{ 0, 1,     1, 2,	    1,2,        3,3,      4,5 }, //koopa
	{ 0, 1,     1, 2,       0,1,        1,4,      4,5 }, // plant
	{ 0, 1,     1, 2,       2,3,        3,4,      5,6 }, // wizard
	{ 0, 1,     1, 2,	    1,2,        1,3,      4,5 }  // bowser
};

WriteAttackMainWin::WriteAttackMainWin( QWidget *parent ) :
    QMainWindow( parent ),
    frame(0),
    mascotMood( Mascot_IDLE )

{
	setupUi( this );

	// set font and stuff for main widget
	textEdit->setAcceptRichText( false );	

	// hook up widgets	
	connect( textEdit, SIGNAL(textChanged()), this, SLOT(updateWordCount()) );

	// hook up timers
	connect( &timerCountdown, SIGNAL(timeout()), this, SLOT(updateTick()) );
	connect( &timerUpdateMascotAnim, SIGNAL(timeout()), this, SLOT(updateAnim()) );

	connect( actionSave, SIGNAL(triggered()), this, SLOT( doSave() ) );
	connect( actionAbout, SIGNAL(triggered()), this, SLOT( about() ) );

	connect( btnStart, SIGNAL( pressed() ), this, SLOT( doTimerButton() ) );

	connect( btnSetTargets, SIGNAL( pressed() ), this, SLOT( doSetTargets() ) );

	connect( textEdit, SIGNAL( burningDone() ), this, SLOT( onBurnComplete() ) );
	

	timerUpdateMascotAnim.start( 300 );

	// defaults
	timeLimit = 10;
	strcpy( mascotName, "yoshi" );
	mascotIndex = 0;

	needsReset = false;
	isBurning = false;
	success = false;

	// fill in the mascot pic
	updateAnim();
} 


void WriteAttackMainWin::startWriting()
{
	statusBar()->showMessage( tr("Timer will start automatically once 10 words have been typed." ));

	// use the "format" to show the number of seconds
	resetTimer();

	timerCountdown.setInterval( 1000 );
	timerCountdown.setSingleShot( false );
}

void WriteAttackMainWin::updateWordCount()
{
	if (isBurning) return;

	const QTextDocument *doc = textEdit->document();	

	// Just do this the slow way... if it's too slow, 
	// figure out what the fast way is...
	QString docText = doc->toPlainText();

	int wordCount = 0;
	bool inWhitespace = true;
	for (int i=0; i < docText.length(); i++)
	{
		QChar ch = docText[i];
		bool isWS = ((ch==' ')||(ch=='\t')||(ch=='\n')||(ch=='-'));
		
		if ((inWhitespace) && (!isWS))
		{
			wordCount++;
			inWhitespace = false;
		}
		else if ((!inWhitespace) && (isWS))
		{
			inWhitespace = true;
		}
		// else no change
	}
	
	// Update based on word count
	lcdWordCount->display( wordCount );	

	int targWords = lcdTarget->intValue();
	int wordsLeft = targWords - wordCount;
	if (wordsLeft > 0)
	{
		lcdWordsLeft->display( wordsLeft );
	}
	else
	{
		lcdWordsLeft->display( 0 );

		// Yay goal is met... resetify things.
		statusBar()->showMessage( "Target reached! Save and Copy are reactivated.\n" );	
		unlockDown();
		mascotMood = Mascot_HAPPY;
		success = true;

		// Restore the start button
		btnStart->setText( "Reset" );
		needsReset = true;
	}


	if ((!needsReset) && (wordCount == 10) && (!textEdit->lockdown() ) )
	{
		startTimer();		
	}
}

void WriteAttackMainWin::startTimer()
{
	statusBar()->showMessage("Countdown started! Save/Copy disabled!", 2000 );
		
	// lockdown and start timer
	timerCountdown.start();
	btnStart->setText( "Stop Timer" );

	lockDown();
}

void WriteAttackMainWin::updateTick()
{
	// count 
	--secondsLeft;	

	// update time left bar	
	QString timeLabel;
	timeLabel.sprintf( "%02d:%02d", secondsLeft / 60, secondsLeft % 60 );
//	timeLeft->setFormat( timeLabel );
	timeLeft->setValue( secondsLeft );

    // time left label for mac
    lblTimeLeft->setText( timeLabel );

	// update the velocity for the last 10 seconds
	int wordCount = lcdWordCount->intValue();	
	int wordsLeft = lcdWordsLeft->intValue();

	if (wordsLeft > 0)
	{
		wordCountHistory.push_back(  wordCount );	
	
		if (wordCountHistory.size() > 10)
		{
			// age off the oldest count
			wordCountHistory.pop_front();

			float dwords = wordCountHistory[9] - wordCountHistory[0];

			// bad user.. been deleting words
			if (dwords <= 0)
			{
				dwords = 0;
				mascotMood = Mascot_OUCH;
			}
			else
			{
				// words per second
				float wordVel = dwords / 10.0;
				float wordsExpected = wordsLeft - ( wordVel * secondsLeft);
				float threshold = lcdTarget->intValue() * 0.10; // 10%

				if (wordsExpected > threshold)
				{
					// uh oh.. not enough words.. mascot gets
					// worried.
					mascotMood = Mascot_ATTACK;
				}
				else if (wordsExpected < -threshold)
				{
					// ahead of the target... yay!
					mascotMood = Mascot_HAPPY;
				}
				else
				{
					// safely within the word count
					mascotMood = Mascot_IDLE;
				}			
			}
		}
	}


	// did the timer run out??
	if (secondsLeft<=0)
	{
		timerCountdown.stop();		

		// did the user meet the target??
		if ((!success) && (wordsLeft > 0))
		{
			// Nope... NUKE THEIR TEXT
			textEdit->destroyText();
			isBurning = true;
			mascotMood = Mascot_DEAD;	
		}

		// otherwise the lockdown is 
		// already lifted through victory
		resetTimer();
	}
}

void WriteAttackMainWin::unlockDown()
{
	btnSetTargets->setEnabled( true );	
	btnStart->setEnabled( true );
	actionSave->setEnabled( true );

	textEdit->unlockDown();
}

void WriteAttackMainWin::lockDown()
{
	btnSetTargets->setEnabled( false );
	btnStart->setEnabled( false );

	actionSave->setEnabled( false );

	// Lock down editor so you can't save, cut, copy, etc..
	textEdit->lockDown();
}

void WriteAttackMainWin::doSave()
{	
	if (!textEdit->lockdown())
	{
		QString fileName;
		fileName = QFileDialog::getSaveFileName( this, "Save file as...", "", "Text Files (*.txt)" );

		if (!fileName.isEmpty())
		{
			QFile file( fileName );
			if (file.open( QIODevice::WriteOnly | QIODevice::Text ))
			{
				QTextStream textOut( &file );
				textOut << textEdit->toPlainText();
			}
		}
	}
}

void WriteAttackMainWin::doTimerButton()
{
	if (needsReset)
	{
		if (timerCountdown.isActive() )
		{
			timerCountdown.stop();			
		}

		textEdit->clear();				
		mascotMood = Mascot_IDLE;
		startWriting();
		
		wordCountHistory.clear();
		btnStart->setText( "Start!" );
		needsReset = false;
		success = false;
	}
	else
	{
		if (!timerCountdown.isActive() )
		{
			startTimer();
		}
		else
		{
			// user is already met goal..stop timer voluntarily
			timerCountdown.stop();
			resetTimer();
		}
	}
}

void WriteAttackMainWin::resetTimer()
{
	QString timeLabel;
	timeLabel.sprintf( "%02d:00", timeLimit );
//	timeLeft->setFormat( timeLabel );
    lblTimeLeft->setText(timeLabel);

	secondsLeft = timeLimit * 60;
	timeLeft->setMinimum( 0 );
	timeLeft->setMaximum( timeLimit * 60 );
	timeLeft->setValue( secondsLeft );	
}

void WriteAttackMainWin::updateAnim()
{
	frame += 1;
	if (frame==2) frame = 0;

	QString iconName;
	iconName.sprintf( ":/anims/mascots/%s_frame%02d.png", mascotName, 
		mascotFrames[mascotIndex][mascotMood *2 + frame] );	
	lblMascot->setPixmap(QPixmap(iconName));
}

void WriteAttackMainWin::keyPressEvent( QKeyEvent *event )
{
	// debug codes for testing without having to type a few
	// pages every run
#ifndef QT_NO_DEBUG
	if ( (event->key() == Qt::Key_T) && (event->modifiers() & Qt::ControlModifier) )
	{
		printf("DBG: debug timeout\n" );
		secondsLeft = 10;
		event->accept();
	}
	else if ( (event->key() == Qt::Key_E) && (event->modifiers() & Qt::ControlModifier) )
	{
		printf("DBG: easy finish\n" );
		int wordCount = lcdWordCount->intValue();
		lcdTarget->display( wordCount + 3 );
		event->accept();
	}
	else if (event->key() == Qt::Key_F1)
	{
		mascotMood = Mascot_IDLE;
		printf("idle\n" );
		event->accept();
	}
	else if (event->key() == Qt::Key_F2)
	{
		mascotMood = Mascot_ATTACK;
		printf("attack\n" );
		event->accept();
	}
	else if (event->key() == Qt::Key_F3) 
	{
		mascotMood = Mascot_HAPPY;
		event->accept();
	}
	else if (event->key() == Qt::Key_F4)
	{
		mascotMood = Mascot_OUCH;
		event->accept();
	}
	else if (event->key() == Qt::Key_F5)
	{
		mascotMood = Mascot_DEAD;
		event->accept();
	}
	else if (event->key() == Qt::Key_F6)
	{
		printf("Destroy text\n" );
		textEdit->destroyText();
		isBurning = true;
		event->accept();
	}
	else 
#endif
		event->ignore();	
}

void WriteAttackMainWin::doSetTargets()
{
	TargetWordsDialog dlg( this, lcdTarget->intValue(), timeLimit );

	timerCountdown.stop();
	timerUpdateMascotAnim.stop();

	if (dlg.exec())
	{
		lcdTarget->display( dlg.getWordCount() );
		timeLimit = dlg.getTimeLimit();

		dlg.getCurrentMascot( mascotIndex, mascotName );
		mascotMood = Mascot_IDLE;
		updateAnim();

		resetTimer();
	}
	timerUpdateMascotAnim.start();
}

void WriteAttackMainWin::onBurnComplete()
{
	// raise the lockDown
	unlockDown();	

	// Restore the start button
	btnStart->setText( "Reset" );
	needsReset = true;
	isBurning = false;
}

void WriteAttackMainWin::about()
{
	QMessageBox mbAbout(
			QMessageBox::NoIcon, tr("About WriteAttack"),
			tr("<center><img src=\":/app/write-attack-logo.png\"><br><hr>"
            "WriteAttack v1.0<br>"
            "by Joel Davis (joeld42@gmail.com)<br>"
            "<hr>Visit project website at:<br><a href=\"http://www.tapnik.com/write-attack/\">"
            "http://www.tapnik.com/write-attack/</a><hr></center>"
				), QMessageBox::Ok );
	mbAbout.setWindowIcon(QIcon(QString::fromUtf8(":/app/write-attack-icon64.png")));
	mbAbout.exec();
	
}
